//
//  SocketClientManage.m
//  Calibration
//
//  Created by ViKing Lai on 2018/1/24.
//  Copyright © 2018年 ViKing Lai. All rights reserved.
//

#import "SocketClient.h"
#import "HiperTimer.h"

@interface SocketClient()
{
    NSString *_ipAddress ;
    NSUInteger _port ;
    GCDAsyncSocket *clientSocket ;
    NSString *errorInfo ;
    id delegate ;
    NSMutableString *tempStoreReceiveData ;
    NSMutableData *tempStoreReceiveDataByte ;
    NSMutableData *tempStoreDatas ;
    BOOL isConnected ;
    BOOL isAutoRelinkWhenLost ;
    
    NSFileHandle* _fileHandle;
    NSDateFormatter* _formatter;
    NSString *_logPath ;
    BOOL isFirstLink ;
    BOOL mStopped;
    NSMutableString* strResult ;

}
@property (assign) BOOL enQueue;

@end

@implementation SocketClient

@synthesize enQueue;

-(id)init
{
    if (self = [super init]) {
        tempStoreReceiveData = [[NSMutableString alloc] init] ;
        tempStoreReceiveDataByte = [[NSMutableData alloc] init] ;
        tempStoreDatas = [[NSMutableData alloc] init] ;
        isConnected = NO ;
        isAutoRelinkWhenLost = YES ;
        isFirstLink = YES ;
        mStopped = NO ;
        strResult = [[NSMutableString alloc] init];
        isConnected = [self connect] ;

    }
    return self;
}

-(instancetype)initClient:(NSString *)ipAddress andPort:(NSUInteger)port andDelegate:(id)dele
{
    if(self = [super init])
    {
        _ipAddress = ipAddress ;
        _port = port ;
        errorInfo = @"" ;
        delegate = dele ;
        tempStoreReceiveData = [[NSMutableString alloc] init] ;
        tempStoreReceiveDataByte = [[NSMutableData alloc] init] ;
        tempStoreDatas = [[NSMutableData alloc] init] ;
        isConnected = NO ;
        isAutoRelinkWhenLost = YES ;
        isFirstLink = YES ;
        mStopped = NO ;
        strResult = [[NSMutableString alloc] init];
        isConnected = [self connect] ;
    }
    
    return self ;
}

-(instancetype)initClient:(NSString *)ipAddress andPort:(NSUInteger)port
{
    if(self = [super init])
    {
        _ipAddress = ipAddress ;
        _port = port ;
        errorInfo = @"" ;
        tempStoreReceiveData = [[NSMutableString alloc] init] ;
        tempStoreReceiveDataByte = [[NSMutableData alloc] init] ;
        isConnected = NO ;
        isAutoRelinkWhenLost = YES ;
        _logPath = nil ;
        _fileHandle = nil ;
        _formatter = [[NSDateFormatter alloc] init];
        [_formatter setDateFormat:@"[yyyy-MM-dd HH:mm:ss]: "];
        isFirstLink = YES ;
        [tempStoreReceiveData setString:@""];
        
        isConnected = [self connect] ;
    }
    
    return self ;
}



-(void)write:(NSString *)msg
{
    
}
-(BOOL)isDisConnect
{
    isConnected = NO;
    return isConnected;
}

-(BOOL)connect
{
    if(isConnected)
    {
        return YES ;
    }
    
    BOOL flag = YES ;
    clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()] ;
    NSError *err = nil ;
    
    if(![clientSocket connectToHost:[NSString stringWithFormat:@"%@",@"169.254.0.1"] onPort:5025 error:&err])
    {
        flag = NO ;
        errorInfo = err.description ;
        
    }
    else
    {
        [clientSocket readDataWithTimeout:-1 tag:1] ;
    }
    
    return flag ;
}


-(BOOL)isConnected
{
    return isConnected ;
}

-(NSString *)getErrorInfo
{
    return errorInfo ;
}

-(void)setAutoRelink:(BOOL)isAutoRelink
{
    isAutoRelinkWhenLost = isAutoRelink ;
}

//receive data and store it in tempStoreReceiveData
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    if(_port == 8088){
        
        [tempStoreDatas appendData:data] ;
    }
    
    NSString *receive = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] ;
    if([self checkIfContainIligalChar:data] == false){
        if (tempStoreReceiveData == nil) {
            tempStoreReceiveData = [NSMutableString new];
        }
        [tempStoreReceiveData appendString:receive] ;
    }
    else{
    }
    [sock readDataWithTimeout:-1 tag:1] ;
}

-(void)sendData:(NSString *)data
{
    if(data == nil || [data isEqualToString:@""])
    {
        return ;
    }

    [clientSocket writeData:[data dataUsingEncoding:NSUTF8StringEncoding] withTimeout:1 tag:0] ;
}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
     [sock readDataWithTimeout:-1 tag:1] ;
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    isConnected = YES ;
    
    if(!isFirstLink)
    {
        [self write:[NSString stringWithFormat:@"%@ have reconnected",host]] ;
    }
    
    isFirstLink = NO ;
    
}


-(void)loadBoard
{
    
    while (![tempStoreReceiveData containsString:@"password:"]) {
        [NSThread sleepForTimeInterval:0.1] ;
    }
    
    [tempStoreReceiveData setString:@""] ;
    
    while (![tempStoreReceiveData containsString:@"FPGA:"]) {
        [NSThread sleepForTimeInterval:0.1] ;
    }
    
    
    [tempStoreReceiveData setString:@""] ;
    isConnected = YES ;
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err
{
    isConnected = NO ;
    
    if(isAutoRelinkWhenLost)
    {
        [NSThread detachNewThreadSelector:@selector(reConnect:) toTarget:self withObject:err] ;
    }
}


-(void)reConnect:(NSError*)err
{
    [NSThread sleepForTimeInterval:3] ;
    
    if(!isFirstLink)
    {
        [self write:[NSString stringWithFormat:@"%@ have disconnected",_ipAddress]] ;
    }
    
    if(![clientSocket connectToHost:_ipAddress onPort:_port error:&err])
    {
        errorInfo = err.description ;
        
    }
    else
    {
        [clientSocket readDataWithTimeout:-1 tag:0] ;
    }
}


-(NSString *)getAllData
{
    NSString *strRtn = [tempStoreReceiveData copy] ;
    [tempStoreReceiveData setString:@""] ;
    if(strRtn != nil && strRtn.length > 0){
    }
    
    return strRtn ;
}



-(NSData *)getAllDataByte
{
    NSData *data = [[NSData alloc] initWithData:tempStoreDatas] ;
    
    if([data length] > 0){
    }
    if(_port == 8088){
        tempStoreDatas  = [[NSMutableData alloc] init] ;
    }

    
    return data ;
}

-(void)disconnect
{
    isAutoRelinkWhenLost = NO ;
    [clientSocket disconnect] ;
}

-(NSString*)ReadTo:(NSString *)data timeOut:(double)timeout Interval:(double)interval
{
    if([data length] == 0)
    {
        
        return @"" ;
    }
    
    NSMutableString* result = [[NSMutableString alloc] init];
    HiperTimer* hp = [[HiperTimer alloc] init];
    [hp start];

    while (isConnected &&!mStopped)
    {
        [NSThread sleepForTimeInterval:0.05] ;

        if ([tempStoreReceiveData containsString:data]) {
            break;
        }
        
        
        NSInteger time = [hp durationMillisecond];
        if(time >= timeout)
        {
            break;
        }
        
    }
    
    [result appendString:[tempStoreReceiveData copy]] ;
    [tempStoreReceiveData setString:@""] ;
    
    return result;
}


-(NSString*)ReadRegularLen:(int)len timeOut:(double)timeout Interval:(double)interval
{
    if(len <= 0)
    {
        return @"" ;
    }
    
    NSMutableString* result = [[NSMutableString alloc] init] ;
    
    while (isConnected && !mStopped) {
        
        if(tempStoreReceiveData.length >= len)
        {
            break ;
        }
        
        [NSThread sleepForTimeInterval:interval] ;
    }
    
    [result appendString:tempStoreReceiveData] ;
    [tempStoreReceiveData setString:@""] ;
    
    return result ;
}

-(NSString*)ReadRegularFormat:(NSString *)format timeOut:(double)timeout Interval:(double)interval
{
    if([format length] == 0)
    {
        return @"";
    }
    
    NSRange range = NSMakeRange(-1, 0);
    NSMutableString* result = [[NSMutableString alloc] init];
    NSError* err = [[NSError alloc] init] ;
    NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:format options:0 error:&err];
    
    while (isConnected )
    {
        range = [regex rangeOfFirstMatchInString:tempStoreReceiveData options:0 range:NSMakeRange(0, tempStoreReceiveData.length)];
        
        if (range.length > 0) {
            break;
        }
        
        
        [NSThread sleepForTimeInterval:interval];
    }
    
    [result appendString:tempStoreReceiveData] ;
    [tempStoreReceiveData setString:@""] ;
    
    return result;
}

/*
 * Para1 : data, a string need looking for
 * Para2 : subStr, seperator ,eg ","
 * Para3 : timeout, millisecond ,
 * Para4 : interval, second 
 */

-(NSString*)ReadMutableEndStr:(NSString *)data andSubStr:(NSString *)subStr timeOut:(double)timeout Interval:(double)interval
{
    if([data length] == 0)
    {
        return @"" ;
    }
    
    NSMutableString* result = [[NSMutableString alloc] init] ;
    NSArray* array = [data componentsSeparatedByString:subStr] ;
    HiperTimer* hp = [[HiperTimer alloc] init] ;
    NSRange range ;
    
    while (isConnected)
    {
        for (NSString* str in array)
        {
            range = [tempStoreReceiveData rangeOfString:str] ;
            
            if(range.length > 0)
            {
                break ;
            }
        }
        
        if([hp durationMillisecond] >= timeout)
        {
            break ;
        }
        
        [NSThread sleepForTimeInterval:interval] ;
    }
    
    [result appendString:tempStoreReceiveData] ;
    [tempStoreReceiveData setString:@""] ;
    
    return result ;
}


//get Data from socket
-(BOOL)ReadSocketPort:(double)tt  usingBlock:(void (^)(NSData *data,size_t len,BOOL *stop))callback;
{
    BOOL status = YES;
    NSString *recvString = nil;
    NSDate *start = [NSDate date];
    BOOL stopFlag=NO;
    [self setEnQueue:YES];
    do {
        recvString = tempStoreReceiveData;
        if (recvString != nil && [recvString length] > 0) {
            NSData *recvData = [[NSData alloc] initWithBytes:[recvString UTF8String]
                                                      length:[recvString length]];
            callback(recvData,[recvData length], &stopFlag);
        }
        else {
            [NSThread sleepForTimeInterval:0.001];
        }
    } while ([[NSDate date] timeIntervalSinceDate: start] < tt && stopFlag == NO);
    
    return status;
}

-(NSString*)infoProcess:(NSString*)infoMsg
{
    NSString* returnValue  ;
    
    return returnValue ;
}

- (bool)checkIfContainIligalChar:(NSData *)data
{
    bool bFindIligalCharecter = NO;
    NSMutableData *md = [NSMutableData dataWithData:data];
    int loc = 0;
    while(loc < [md length])
    {
        char buffer;
        [md getBytes:&buffer range:NSMakeRange(loc, 1)];
        if((buffer & 0x80) == 0)
        {
            loc++;
            continue;
        }
        else if((buffer & 0xE0) == 0xC0)
        {
            loc++;
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if((buffer & 0xC0) == 0x80)
            {
                loc++;
                continue;
            }
            loc--;
            //非法字符，将这个字符（一个byte）替换为A
            return  YES;
        }
        else if((buffer & 0xF0) == 0xE0)
        {
            loc++;
            [md getBytes:&buffer range:NSMakeRange(loc, 1)];
            if((buffer & 0xC0) == 0x80)
            {
                loc++;
                [md getBytes:&buffer range:NSMakeRange(loc, 1)];
                if((buffer & 0xC0) == 0x80)
                {
                    loc++;
                    continue;
                }
                loc--;
            }
            loc--;
            //非法字符，将这个字符（一个byte）替换为A
            return  YES;
        }
        else
        {
            //非法字符，将这个字符（一个byte）替换为A
            return  YES;
        }
    }
    
    return bFindIligalCharecter;
}


@end
